<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>

                    <h4>使用Web框架</h4>
                    <div class="x-wiki-info"><span>1015次阅读</span></div>
                    <hr style="border-top-color:#ccc" />
                    <div class="x-wiki-content x-content"><p>了解了WSGI框架，我们发现：其实一个Web App，就是写一个WSGI的处理函数，针对每个HTTP请求进行响应。</p>
<p>但是如何处理HTTP请求不是问题，问题是如何处理100个不同的URL。</p>
<p>每一个URL可以对应GET和POST请求，当然还有PUT、DELETE等请求，但是我们通常只考虑最常见的GET和POST请求。</p>
<p>一个最简单的想法是从<code>environ</code>变量里取出HTTP请求的信息，然后逐个判断：</p>
<pre><code>def application(environ, start_response):
    method = environ[&#39;REQUEST_METHOD&#39;]
    path = environ[&#39;PATH_INFO&#39;]
    if method==&#39;GET&#39; and path==&#39;/&#39;:
        return handle_home(environ, start_response)
    if method==&#39;POST&#39; and path=&#39;/signin&#39;:
        return handle_signin(environ, start_response)
    ...
</code></pre><p>只是这么写下去代码是肯定没法维护了。</p>
<p>代码这么写没法维护的原因是因为WSGI提供的接口虽然比HTTP接口高级了不少，但和Web App的处理逻辑比，还是比较低级，我们需要在WSGI接口之上能进一步抽象，让我们专注于用一个函数处理一个URL，至于URL到函数的映射，就交给Web框架来做。</p>
<p>由于用Python开发一个Web框架十分容易，所以Python有上百个开源的Web框架。这里我们先不讨论各种Web框架的优缺点，直接选择一个比较流行的Web框架——<a href="http://flask.pocoo.org/">Flask</a>来使用。</p>
<p>用Flask编写Web App比WSGI接口简单（这不是废话么，要是比WSGI还复杂，用框架干嘛？），我们先用<code>easy_install</code>或者<code>pip</code>安装Flask：</p>
<pre><code>$ easy_install flask
</code></pre><p>然后写一个<code>app.py</code>，处理3个URL，分别是：</p>
<ul>
<li><p><code>GET /</code>：首页，返回<code>Home</code>；</p>
</li>
<li><p><code>GET /signin</code>：登录页，显示登录表单；</p>
</li>
<li><p><code>POST /signin</code>：处理登录表单，显示登录结果。</p>
</li>
</ul>
<p>注意噢，同一个URL<code>/signin</code>分别有GET和POST两种请求，映射到两个处理函数中。</p>
<p>Flask通过Python的<a href="/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386819879946007bbf6ad052463ab18034f0254bf355000">装饰器</a>在内部自动地把URL和函数给关联起来，所以，我们写出来的代码就像这样：</p>
<pre><code>from flask import Flask
from flask import request

app = Flask(__name__)

@app.route(&#39;/&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def home():
    return &#39;&lt;h1&gt;Home&lt;/h1&gt;&#39;

@app.route(&#39;/signin&#39;, methods=[&#39;GET&#39;])
def signin_form():
    return &#39;&#39;&#39;&lt;form action=&quot;/signin&quot; method=&quot;post&quot;&gt;
              &lt;p&gt;&lt;input name=&quot;username&quot;&gt;&lt;/p&gt;
              &lt;p&gt;&lt;input name=&quot;password&quot; type=&quot;password&quot;&gt;&lt;/p&gt;
              &lt;p&gt;&lt;button type=&quot;submit&quot;&gt;Sign In&lt;/button&gt;&lt;/p&gt;
              &lt;/form&gt;&#39;&#39;&#39;

@app.route(&#39;/signin&#39;, methods=[&#39;POST&#39;])
def signin():
    # 需要从request对象读取表单内容：
    if request.form[&#39;username&#39;]==&#39;admin&#39; and request.form[&#39;password&#39;]==&#39;password&#39;:
        return &#39;&lt;h3&gt;Hello, admin!&lt;/h3&gt;&#39;
    return &#39;&lt;h3&gt;Bad username or password.&lt;/h3&gt;&#39;

if __name__ == &#39;__main__&#39;:
    app.run()
</code></pre><p>运行<code>python app.py</code>，Flask自带的Server在端口<code>5000</code>上监听：</p>
<pre><code>$ python app.py 
 * Running on http://127.0.0.1:5000/
</code></pre><p>打开浏览器，输入首页地址<code>http://localhost:5000/</code>：</p>
<p><img src="http://www.liaoxuefeng.com/files/attachments/00140033505820757c3cd7cc6844ee9abd7ce64d7b36fb5000" alt="flask-home"></p>
<p>首页显示正确！</p>
<p>再在浏览器地址栏输入<code>http://localhost:5000/signin</code>，会显示登录表单：</p>
<p><img src="http://www.liaoxuefeng.com/files/attachments/0014003351105577b45a8b4b82b40438315bb2200e2ef50000" alt="flask-signin-form"></p>
<p>输入预设的用户名<code>admin</code>和口令<code>password</code>，登录成功：</p>
<p><img src="http://www.liaoxuefeng.com/files/attachments/00140033516145372d91191c0674dadbc892cbb7934f041000" alt="flask-signin-ok"></p>
<p>输入其他错误的用户名和口令，登录失败：</p>
<p><img src="http://www.liaoxuefeng.com/files/attachments/0014003351721702afa8e2086de43cabc1e0b0ba930a432000" alt="flask-signin-failed"></p>
<p>实际的Web App应该拿到用户名和口令后，去数据库查询再比对，来判断用户是否能登录成功。</p>
<p>除了Flask，常见的Python Web框架还有：</p>
<ul>
<li><p><a href="https://www.djangoproject.com/">Django</a>：全能型Web框架；</p>
</li>
<li><p><a href="http://webpy.org/">web.py</a>：一个小巧的Web框架；</p>
</li>
<li><p><a href="http://bottlepy.org/">Bottle</a>：和Flask类似的Web框架；</p>
</li>
<li><p><a href="http://www.tornadoweb.org/">Tornado</a>：Facebook的开源异步Web框架。</p>
</li>
</ul>
<p>当然了，因为开发Python的Web框架也不是什么难事，我们后面也会自己开发一个Web框架。</p>
<h3 id="-">小结</h3>
<p>有了Web框架，我们在编写Web应用时，注意力就从WSGI处理函数转移到URL+对应的处理函数，这样，编写Web App就更加简单了。</p>
<p>在编写URL处理函数时，除了配置URL外，从HTTP请求拿到用户数据也是非常重要的。Web框架都提供了自己的API来实现这些功能。Flask通过<code>request.form[&#39;name&#39;]</code>来获取表单的内容。</p>
</div>

                    <hr style="border-top-color:#ccc" />

                    